package com.amos.generate.service;

import com.amos.generate.bean.BaseField;
import com.amos.generate.bean.BeanField;
import com.amos.generate.bean.EntityField;
import com.amos.generate.type.TemplateTypeEnum;
import com.amos.generate.util.VelocityUtils;
import com.amos.util.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;

/**
 * Copyright © 2018 嘉源锐信. All rights reserved.
 *
 * @Project: mu-exam
 * @ClassName: AbstractHandler
 * @Package: com.amos.generate.service
 * @author: zhuqb
 * @Description:
 * @date: 2020/3/10 0010 下午 15:48
 * @Version: V1.0
 */
public abstract class AbstractHandler<T extends BaseField> {

    private static final Logger logger = LoggerFactory.getLogger(AbstractHandler.class);
    /**
     * 文件生成保存的路径
     */
    private String path;
    /**
     * 文件保存的根包路径
     */
    private String rootPackageName;
    /**
     * 数据库对应的表名
     */
    private String tableName;
    /**
     * 模板类型
     */
    private TemplateTypeEnum templateType;

    private Class<?> beanClass;

    public AbstractHandler(String path, String rootPackageName, String tableName,TemplateTypeEnum templateType) {
        this.path = path;
        this.rootPackageName = rootPackageName;
        this.tableName = tableName;
        this.templateType = templateType;
        beanClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    /**
     * 获取BaseField字段内容
     * @return
     */
    public abstract T field();
    /**
     * 代码生成
     */
    public void handle() {
        // 初始化参数
        VelocityEngine velocityEngine = VelocityUtils.getVelocityEngine();
        StringWriter stringWriter = new StringWriter();
        BaseField t = this.field();
        t.setModuleName(getModuleName());
        VelocityContext context = VelocityUtils.parseFieldToVelocityContext(t);

        this.initVelocityContext(context,t);

        velocityEngine.mergeTemplate(getTemplate(), "UTF-8", context, stringWriter);

        this.writeToFile(getFile(), stringWriter.toString());
    }



    private void initVelocityContext(VelocityContext context, BaseField t){
        context.put("author", t.getAuthor());
        context.put("datetime", t.getDatetime());
        context.put("upperClassName",this.getUpperClassName());
        context.put("className",this.getClassName());
        context.put("packageName", this.rootPackageName);
        context.put("tableName",this.tableName);
    }

    /**
     * 内容写入到文件
     *
     * @param file
     * @param content
     */
    private void writeToFile(File file, String content) {
        // 先创建文件夹以及对应的文件
        VelocityUtils.createFile(file);
        FileWriter writer = null;
        try {
            writer = new FileWriter(file);
            writer.write("");
            writer.write(content);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }


    public String getTemplate() {
        switch (templateType) {
            case CONTROLLER:
                return "vm/controller.java.vm";
            case SERVICE:
                return "vm/service.java.vm";
            case SERVICEIMPL:
                return "vm/serviceImpl.java.vm";
            case ENTITY:
                return "vm/entity.java.vm";
            case DTO:
                return "vm/dto.java.vm";
            case MAPPER:
                return "vm/mapper.java.vm";
            case XML:
                return "vm/mapper.xml.vm";
            default:
                return null;
        }
    }

    /**
     * 子类可以重写该方法，实现自己的路模板路径
     *
     * @return
     */
    public File getFile() {
        return new File(getFileName());
    }

    /**
     * 获取相对路径名称
     *
     * @return
     */
    private String getRelativePath() {
        switch (templateType) {
            case CONTROLLER:
                return VelocityConstants.CONTROLLER_NAME;
            case SERVICE:
                return VelocityConstants.SERVICE_NAME;
            case SERVICEIMPL:
                return VelocityConstants.SERVICEIMPL_NAME;
            case ENTITY:
                return VelocityConstants.ENTITY_NAME;
            case DTO:
                return VelocityConstants.DTO_NAME;
            case MAPPER:
                return VelocityConstants.MAPPER_NAME;
            case XML:
                return VelocityConstants.MAPPER_NAME;
            default:
                return null;
        }
    }

    /**
     * 获取前缀路径
     * @return
     */
    public String getPrefixPath() {
        return path + File.separator;
    }

    /**
     * 获取包名前缀路径
     * @return
     */
    public String getPackagePrefixPath(){
        return getPrefixPath()+getJavaPath()+VelocityUtils.packageName2Dir(rootPackageName) + File.separator+getModuleName()+File.separator+getRelativePath() + File.separator;
    }

    private String getMainPath(){
        return "src"+File.separator+"main"+File.separator;
    }

    private String getJavaPath(){
        return getMainPath()+"java" + File.separator;
    }

    private String getResourcesPath(){
        return getMainPath()+"resources" + File.separator;
    }
    /**
     * 获取
     * @return
     */
    protected String getXmlPrefixPath() {
        return getPrefixPath()+getResourcesPath()+File.separator+"mapper"+File.separator+getModuleName()+File.separator;
    }

    private String getModuleName(){
        return tableName.split("_")[0];
    }
    /**
     * 获取 文件名
     *
     * @return
     */
    private String getFileName() {
        String prefixPackageName = getPackagePrefixPath();
        switch (templateType) {
            case CONTROLLER:
                return prefixPackageName + StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + "Controller.java";
            case SERVICE:
                return prefixPackageName + StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + "Service.java";
            case SERVICEIMPL:
                return prefixPackageName + StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + "ServiceImpl.java";
            case ENTITY:
                return prefixPackageName + StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + "Entity.java";
            case DTO:
                return prefixPackageName + StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + "DTO.java";
            case MAPPER:
                return prefixPackageName + StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + "Mapper.java";
            case XML:
                return getXmlPrefixPath()+StringUtils.toUpperCaseFirstOne(VelocityUtils.underline2Camel(tableName)) + ".xml";
            default:
                return null;
        }
    }

    /**
     * 将表名转为驼峰格式
     * @return
     */
    public String getClassName(){
        return VelocityUtils.underline2Camel(this.tableName);
    }

    /**
     * 获取实体类名称
     * className首字母大写
     * @return
     */
    public String getUpperClassName(){
        return StringUtils.toUpperCaseFirstOne(this.getClassName());
    }
}
